package com.leetcode.code;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;

/**
 * Description:
 *
 * @author zkingcobra
 * Date: 2020/6/9 11:13 上午
 */
public class LeetCode1115Java {

    public static void main(String[] args) {
        FooBar fooBar = new FooBar(3);
        new Thread(() -> {
            try {
                fooBar.foo(new Runnable() {
                    @Override public void run() {
                        System.out.print("foo");
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                fooBar.bar(new Runnable() {
                    @Override public void run() {
                        System.out.print("bar");
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    static class FooBar {
        private final int n;
        private final CyclicBarrier mBarrier;
        private CountDownLatch mDownLatch;

        public FooBar(int n) {
            this.n = n;

            mBarrier = new CyclicBarrier(2);

            mDownLatch = new CountDownLatch(1);
        }

        public void foo(Runnable printFoo) {
            try {
                for (int i = 0; i < n; i++) {
                    // printFoo.run() outputs "foo". Do not change or remove this line.
                    printFoo.run();
                    mDownLatch.countDown();
                    mBarrier.await();
                }
            } catch (Exception e) {
            }
        }

        public void bar(Runnable printBar) {

            try {
                for (int i = 0; i < n; i++) {
                    mDownLatch.await();
                    // printBar.run() outputs "bar". Do not change or remove this line.
                    printBar.run();
                    mDownLatch = new CountDownLatch(1);
                    mBarrier.await();
                }
            } catch (Exception e) {
            }
        }
    }

    /**
     * 方案：Semaphore信号量
     */
    static class FooBar2 {
        private final int n;
        // 同时只能有一个线程访问
        Semaphore foo = new Semaphore(1);
        // 没有释放前不允许访问
        Semaphore bar = new Semaphore(0);

        public FooBar2(int n) {
            this.n = n;
        }

        public void foo(Runnable printFoo) throws InterruptedException {
            for (int i = 0; i < n; i++) {
                foo.acquire();
                printFoo.run();
                bar.release();
            }
        }

        public void bar(Runnable printBar) throws InterruptedException {
            for (int i = 0; i < n; i++) {
                bar.acquire();
                printBar.run();
                foo.release();
            }
        }
    }
}
